package com.happy3w.task.composer;

import com.happy3w.toolkits.reflect.ReflectUtil;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

public class MethodTask extends Task {
    private final TaskDataMode inputMode;
    private final TaskDataMode outputMode;
    private final Object taskActor;
    private final Method taskAction;

    public MethodTask(List<TaskDataDef> inputs, TaskDataMode inputMode,
                      List<TaskDataDef> outputs, TaskDataMode outputMode,
                      Object taskActor, Method taskAction) {
        super(inputs, outputs);
        this.inputMode = inputMode;
        this.outputMode = outputMode;
        this.taskActor = taskActor;
        this.taskAction = taskAction;
    }

    public static MethodTask from(Method taskAction, Object actor, List<TaskDataDef> inputs, List<TaskDataDef> outputs) {
        TaskDataMode inputMode;
        if (inputs.size() <= 1 || taskAction.getParameterCount() > 1) {
            inputMode = TaskDataMode.ArrayMode;
        } else {
            inputMode = TaskDataMode.MapMode;
        }

        TaskDataMode outputMode;
        if (outputs.size() <= 1) {
            outputMode = TaskDataMode.SingleMode;
        } else if (Map.class.isAssignableFrom(taskAction.getReturnType())) {
            outputMode = TaskDataMode.MapMode;
        } else {
            outputMode = TaskDataMode.ArrayMode;
        }
        return new MethodTask(inputs, inputMode,
                outputs, outputMode,
                actor, taskAction);
    }

    @Override
    public void execute(TaskExecuteContext context) {
        Object param = inputMode.createParams(inputs, context);
        Object[] params = (inputMode == TaskDataMode.ArrayMode)
                ? (Object[]) param
                : new Object[] {param};

        Object result = ReflectUtil.invoke(taskAction, taskActor, params);
        outputMode.saveResult(result, outputs, context);
    }
}
